package com.huli.service.impl;

import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.huli.dao.UserMapper;
import com.huli.domain.*;
import com.huli.exception.CustomException;
import com.huli.feign.CarportFeign;
import com.huli.feign.CouponClient;
import com.huli.feign.MemberClient;
import com.huli.feign.OrdersClient;
import com.huli.param.OrdersCreateParam;
import com.huli.param.UserInfoParam;
import com.huli.param.UserLoginParam;
import com.huli.param.UserRegisterParam;
import com.huli.service.CarService;
import com.huli.service.UserService;
import com.huli.utils.JwtUtils;
import com.huli.utils.Result;
import com.huli.utils.TimeUtils;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;

    @Autowired
    RedisTemplate<String, String> redisTemplate;

    @Autowired
    CarService carService;

    @Autowired
    CarportFeign carportFeign;

    @Autowired
    MemberClient memberClient;

    @Autowired
    OrdersClient ordersClient;

    @Autowired
    CouponClient couponClient;

    @Override
    public void register(UserRegisterParam param) {
        User user = new User();
        BeanUtils.copyProperties(param, user);
        user.setUserCheck(0)
                .setUserMoney(new BigDecimal(0.00))
                .setUserInvite(UUID.randomUUID().toString())
                .setUserSource(1000)
                .setUserStatus(0)
                .setUserVipId(0)
                .setUserVipTime(TimeUtils.now());
        userMapper.insert(user);
    }

    @Override
    public String login(UserLoginParam param) {
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("user_account", param.getUserAccount()).eq("user_password", param.getUserPassword()));
        if (user == null) throw new CustomException(Result.failedResult(500, "用户名或者密码错误"));
        String code = redisTemplate.opsForValue().get(user.getUserEmail());
        if (!param.getLoginCode().equals(code)) throw new CustomException(Result.failedResult(500, "验证码错误"));
        return new JwtUtils().generateToken(user.getUserId());
    }

    @Override
    public User getUser(int userId) {
        User user = userMapper.selectById(userId);
        if (user == null) throw new CustomException(Result.failedResult(500, "用户不存在"));
        return user;
    }

    @Override
    public void userRent(OrdersCreateParam param) {
        System.out.println(1);
        Car car = carService.getCar(param.getCarId());
        User user = getUser(car.getUserId());
        Result result = carportFeign.selectCarportById(param.getCarportId());
        Carport carport = Result.getOriginal(result, Carport.class);
        Result byCarportR = ordersClient.getByCarportId(carport.getOwnerId());
        List<Orders> ordersList = Result.getOriginalArray(byCarportR, Orders.class);
        System.out.println(2);
        //计算时间是否符合预定规则
        if (!timeRule(ordersList, param.getStartTime(), param.getEndTime()))
            throw new CustomException(Result.failedResult(300, "订单时间选择错误"));
        //计算优惠券是否符合预定规则
        System.out.println(3);
        if (param.getCouponId() != 0) {
            Result userCouponR = couponClient.getUserCoupon(user.getUserId());
            List<UserCoupon> userCoupons = Result.getOriginalArray(userCouponR, UserCoupon.class);
            boolean bool = false;
            for (UserCoupon userCoupon : userCoupons) {
                if (userCoupon.getCouponId().equals(param.getCouponId()) && userCoupon.getUserCouponNum() >= 1) {
                    couponClient.lessCoupon(userCoupon.getUserCouponId(), 1);
                    System.out.println("优惠券剩余:优惠券id:" + userCoupon.getUserCouponId() + "数量:" + userCoupon.getUserCouponNum());
                    bool = true;
                }
            }
            if (!bool) throw new CustomException(Result.failedResult(500, "用户优惠券不足"));
        }
        System.out.println(4);
        redisTemplate.opsForList().leftPush("rent:carport:" + param.getCarportId(), car.getCarId().toString());
        List<String> range = redisTemplate.opsForList().range("rent:carport:" + param.getCarportId(), 0, 1);
        Assert.notNull(range,"....");
        if (range.get(0).equals(car.getCarId().toString())) {
            System.out.println(5);
            Result ordersR = ordersClient.newOrders(param);
            System.out.println(6);
            //不管生成成功还是失败 队列都会重新启用
            redisTemplate.delete("rent:carport:" + param.getCarportId());
            System.out.println(7);
            if (!ordersR.isSuccess()) throw new CustomException(ordersR);
            System.out.println(8);
        } else {
            throw new CustomException(Result.failedResult(300, "对不起 抢购失败"));
        }
    }


    @Override
    public boolean timeRule(List<Orders> carportOrders, Date startTime, Date endTime) {
        if (startTime.compareTo(endTime) == 0 || !startTime.after(TimeUtils.now()) || endTime.before(startTime))
            return false;
        for (Orders carportOrder : carportOrders) {
            Date ordersStartTime = carportOrder.getOrdersStartTime();
            Date ordersEndTime = carportOrder.getOrdersEndTime();

            //情况1 包含 情况2 左相交 情况3 右相交 情况4 被包含
            if (endTime.before(ordersStartTime) || startTime.after(ordersEndTime)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void changeSource(int userId, int userSource) {
        User user = getUser(userId);
        int update = userMapper.update(User.builder().userSource(userSource).build()
                , new UpdateWrapper<User>().eq("user_id", user.getUserId())
                        .eq("user_source", user.getUserSource()));
        if (update <= 0) throw new CustomException(Result.failedResult(300, "更新失败"));
    }

    @Override
    public void changeStatus() {
        userMapper.updateStatus();
    }

    @Override
    public void changeVip() {
        userMapper.updateVip();
    }

    @Override
    public User getUserByInvite(String userInvite) {
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("user_invite", userInvite));
        if (user == null) throw new CustomException(Result.failedResult(500, "使用该码的用户不存在"));
        return user;
    }

    @Override
    public void buyVip(int userId, int vipId) {
        User user = getUser(userId);
        if (user.getUserVipId() != 0) throw new CustomException(Result.failedResult(300, "用户当前已有VIP"));
        //计算价格
        Result result = memberClient.selectUserVipById(vipId);
        UserVip userVip = Result.getOriginal(result, UserVip.class);
        if (user.getUserMoney().compareTo(userVip.getUserVipPrice()) == -1)
            throw new CustomException(Result.failedResult(300, "账户余额不足"));
        //计算用户余额 以及到期时间
        BigDecimal subtract = user.getUserMoney().subtract(userVip.getUserVipPrice());
        Date dateTime = TimeUtils.addMinute(TimeUtils.now(), userVip.getUserVipTime());
        //更改用户信息
        int update = userMapper.update(user.setUserVipId(vipId).setUserVipTime(dateTime).setUserMoney(subtract)
                , new UpdateWrapper<User>().eq("user_id", user.getUserId()).eq("user_money", user.getUserMoney()));
        if (update <= 0) throw new CustomException(Result.failedResult(000, "更新失败"));
    }

    @Override
    public void changeInfo(UserInfoParam param) {
        param.setUserNickname("'" + param.getUserNickname() + "'");
        userMapper.changeInfo(param);
    }

    @Override
    public void changeMoney(int userId, BigDecimal userMoney) {
        User user = getUser(userId);
        BigDecimal money = user.getUserMoney();
        int update = userMapper.update(user.setUserMoney(userMoney)
                , new UpdateWrapper<User>().eq("user_id", user.getUserId()).eq("user_money", money));
        if (update <= 0) throw new CustomException(Result.failedResult(000, "更新失败"));
    }

    @Autowired
    public List<User> userRecharge() {
        return userMapper.selectList(new QueryWrapper<User>().lt("user_source", 0));
    }
}
